package org.springframework.data.mybatis.repository.support;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

public abstract class SqlSessionRepositorySupport {

	private static final char DOT = '.';

	private final SqlSessionTemplate sqlSession;

	@SuppressWarnings("deprecation")
	protected SqlSessionRepositorySupport(SqlSessionTemplate sqlSessionTemplate) {
		Assert.notNull(sqlSessionTemplate);
		this.sqlSession = sqlSessionTemplate;
	}

	public SqlSession getSqlSession() {
		return this.sqlSession;
	}

	protected abstract String getNamespace();

	protected String getStatement(String partStatement) {
		return getNamespace() + DOT + partStatement;
	}

	protected <T> T selectOne(String statement) {
		return getSqlSession().selectOne(getStatement(statement));
	}

	protected <T> T selectOne(String statement, Object parameter) {
		return getSqlSession().selectOne(getStatement(statement), parameter);
	}

	protected <T> List<T> selectList(String statement) {
		return getSqlSession().selectList(getStatement(statement));
	}

	protected <T> List<T> selectList(String statement, Object parameter) {
		return getSqlSession().selectList(getStatement(statement), parameter);
	}

	protected int insert(String statement) {
		return getSqlSession().insert(getStatement(statement));
	}

	protected int insert(String statement, Object parameter) {
		return getSqlSession().insert(getStatement(statement), parameter);
	}

	protected int update(String statement) {
		return getSqlSession().update(getStatement(statement));
	}

	protected int update(String statement, Object parameter) {
		return getSqlSession().update(getStatement(statement), parameter);
	}

	protected int delete(String statement) {
		return getSqlSession().delete(getStatement(statement));
	}

	protected int delete(String statement, Object parameter) {
		return getSqlSession().delete(getStatement(statement), parameter);
	}

	/**
	 * 计算总数
	 * 
	 * @param pager
	 * @param result
	 * @return
	 */
	protected <X> long calculateTotal(Pageable pager, List<X> result) {
		if (pager.hasPrevious()) {
			if (CollectionUtils.isEmpty(result)) {
				return -1;
			}
			if (result.size() == pager.getPageSize()) {
				return -1;
			}
			return (pager.getPageNumber() - 1) * pager.getPageSize() + result.size();
		}
		if (result.size() < pager.getPageSize()) {
			return result.size();
		}
		return -1;
	}

	/**
	 * 根据分页器查找
	 * 
	 * @param pager
	 *            分页器
	 * @param selectStatement
	 *            select
	 * @param countStatement
	 *            count
	 * @param condition
	 *            条件
	 * @param isEqCondition
	 *            是否全等条件
	 * @param otherParams
	 *            其他参数
	 * @return
	 */
	protected <X, Y> Page<X> findByPager(Pageable pager, String selectStatement, String countStatement, Y condition, boolean isEqCondition, Map<String, Object> otherParams) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("offset", pager.getOffset());
		params.put("pageSize", pager.getPageSize());
		params.put("offsetEnd", pager.getOffset() + pager.getPageSize());
		params.put("_sorts", pager.getSort());
		if (condition != null) {
			params.put(isEqCondition ? "_eq_condition" : "_condition", condition);
		}
		if (!CollectionUtils.isEmpty(otherParams)) {
			params.putAll(otherParams);
		}
		List<X> result = selectList(selectStatement, params);
		long total = calculateTotal(pager, result);
		if (total < 0) {
			total = selectOne(countStatement, params);
		}
		return new PageImpl<X>(result, pager, total);
	}

	protected <X> Page<X> findByPager(Pageable pager, String selectStatement, String countStatement) {
		return findByPager(pager, selectStatement, countStatement, null, true);
	}

	protected <X, Y> Page<X> findByPager(Pageable pager, String selectStatement, String countStatement, Y condition, boolean isEqCondition) {
		return findByPager(pager, selectStatement, countStatement, condition, isEqCondition, null);
	}

}